Redis 构建缓存数据库 6 个难点问题
原题:《基于支付标记化项目使用Redis构建缓存数据库的6个难点问题》
近年来,互联网金融公司飞速发展,无论是业务还是技术都较传统银行业有所区别,比如一年一度的双十一给银行业无疑带来了很大的压力,作为传统的银行业如何从技术上着手,构建处理速度快、系统稳定性高的业务系统,是银行业面临的一大问题。
众所周知,数据库在业务系统中占据了非常重要的地位,互联网业务的数据正以更快的速度在增长,数据类型越来越丰富,这对数据处理的速度和能力提出了更高要求,但关系型数据库在如今浪涌似的交易下极易出现瓶颈,因此互联网公司率先引入了缓存数据库来解决性能问题,在这其中,Redis 是一种开源的内存非关系型数据库,给开发人员带来的体验是颠覆性的。在自始至终的设计过程中,都充分考虑高性能,这使得 Redis 成为当今速度最快的 NoSQL 数据库,也是互联网企业在缓存数据库选型时的第一选择。
我写了一篇文章《redis最佳实践--以支付标记化为例》,以给同行业提供一点借鉴,作为传统的银行业来说,如何使用Redis来构建我们的缓存数据库从而提高我们的系统处理性能。
之后的社区交流活动,我和同行交流了一些经验,互动结束后,我整理了活动中出现的几个重要的难点问题,希望继续给大家一些借鉴和帮助。
1.redis 如何快速查找big key?
redis由于是内存数据库,经常需要查看是什么占用了内存资源。是否有什么方法可以快速找出什么大约是什么键占用了多大的内存
解答:
工作中,经常有些Redis实例使用不恰当,或者对业务预估不准确,或者key没有及时进行处理等等原因,导致某些KEY相当大。
那么大Key会带来哪些问题呢?
如果是集群模式下,无法做到负载均衡,导致请求倾斜到某个实例上,而这个实例的QPS会比较大,内存占用也较多;对于Redis单线程模型又容易出现CPU瓶颈,当内存出现瓶颈时,只能进行纵向库容,使用更牛逼的服务器。
涉及到大key的操作,尤其是使用hgetall、lrange 0 -1、get、hmget 等操作时,网卡可能会成为瓶颈,也会到导致堵塞其它操作,qps 就有可能出现突降或者突升的情况,趋势上看起来十分不平滑,严重时会导致应用程序连不上,实例或者集群在某些时间段内不可用的状态。
假如这个key需要进行删除操作,如果直接进行DEL 操作,被操作的实例会被Block住,导致无法响应应用的请求,而这个Block的时间会随着key的变大而变长。
有以下几种办法可以知道某个Redis实例是否存在大key:
在redis实例上执行bgsave,然后我们对dump出来的rdb文件进行分析,找到其中的大KEY
有个不太推荐的命令,debug object xxx 可以看到这个key在内存中序列化后的大小,当然我们可以通过SCAN+debug object xxx 得到当前实例所有key的大小。
redis-cli 原生自带 –bigkeys 功能,可以找到某个实例 5种数据类型(String、hash、list、set、zset)的最大key。
2.在使用redis的时候如何避免和解决缓存穿透和缓存雪崩问题?
解答:
缓存穿透:一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。如果key对应的value是一定不存在的,并且对该key并发请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。
缓存雪崩:当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。
针对缓存穿透问题,一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。通过这个直接设置的默认值存放到缓存,这样第二次到缓存中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴!
针对缓存雪崩问题,给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。
缓存标记:记录缓存数据是否过期,如果过期会触发通知另外的线程在后台去更新实际key的缓存。
缓存数据:它的过期时间比缓存标记的时间延长1倍,例:标记缓存时间30分钟,数据缓存设置为60分钟。 这样,当缓存标记key过期后,实际缓存还能把旧数据返回给调用端,直到另外的线程在后台更新完成后,才会返回新缓存。
3.redis大key删除时会造成整库堵塞,该问题如何优化?
解答1:
在Redis集群中,应用程序尽量避免使用大键;直接影响容易导致集群的容量和请求出现”倾斜问题“,在实际生产过程中,总会有业务使用不合理,出现这类大键;当DBA发现后推进业务优化改造,然后删除这个大键;如果直接删除它,DEL命令可能阻塞Redis进程数十秒,对应用程序和Redis集群可用性造成严重的影响。
解答2:
直接删除大key是有风险的,key过大,直接删除时会导致Redis阻塞,不同类型的大key有不同的删除方式。
Large Hash Key 可使用hscan命令,每次获取500个字段,再用hdel命令,每次删除1个字段。
Large Set Key 可使用sscan命令,每次扫描集合中500个元素,再用srem命令每次删除一个键。
Large List Key可通过ltrim命令每次删除少量元素。
Large Sorted Set Key使用sortedset自带的zremrangebyrank命令,每次删除top 100个元素。
解答3:
可以从以下方面:
1、业务角度,尽量不要使用大key或对其进行处理
2、在4.x版本之前可通过数据类型对应的参数命令进行操作,例如:针对Large Hash Key ,可使用hscan命令进行操作
3、在4.x版本后可通过UNLINK 命令用于执行大KEY异步删除
4.如何快速的增加redis的节点数?
解答:
因为现阶段比较流行的都是redis 3.0之后的集群架构模式,它提供了灵活的节点扩容和收缩方案。在不影响集群对外服务的情况下,可以为集群添加节点进行扩容也可以对下线节点进行缩容。
扩容集群是分布式存储最常见的需求,Redis集群扩容可以分为如下步骤:
准备新节点:配置和之前集群节点配置基本相同,启动后的新节点会作为孤儿节点运行,没有和其他节点与之通信。
加入集群:我们可以通过CLUSTER MEET命令将新节点加入到集群中或者也可以使用redis专门进行集群管理的工具redis-trib.rb,新加入的节点都是主节点,因为没有负责槽位,所以不能接受任何读写操作,对于新加入的节点,我们可以有两个操作:为新节点迁移槽和数据实现扩容,作为其他主节点的从节点负责故障转移。
迁移槽和数据:当我们将新节点加入集群后,我们就可以将槽和数据迁移到新的节点,迁移的方法也有两种,可以使用redis-trib.rb工具,也可以通过手动命令的方式,但是一般要确保每个主节点负责的槽数是均匀的,因此要使用redis-trib.rb工具来批量完成。
5.reids和memcached如果只有string数据时的话二者的区别是什么,该如何选择?
如果目前两者共存,如何进行收敛(干掉一个)
解答1:
针对分布式缓存库的选择,不仅要考虑产品自身的特性,同时也要考虑业务场景、系统架构层面
解答2:
6.redis有哪些安全特性和加固方法?
解答1:
需要从以下几个方面对redis进行加固,网络层加固,账号与认证,服务运行权限最小化,服务精细化授权,安全补丁
解答2:
redis有两种安全策略方式,一是限制访问ip,二是设置用户名、密码;
注:由于Redis的性能极高,并且输入错误密码后Redis并不会进行主动延迟(考虑到Redis的单线程模型),所以攻击者可以通过穷举法破解Redis的密码(1秒内能够尝试十几万个密码),因此在设置时一定要选择复杂的密码。
配置Redis复制的时候如果主数据库设置了密码,需要在从数据库的配置文件中通过masterauth参数设置主数据库的密码,以使从数据库连接主数据库时自动使用AUTH命令认证。
解答3:
上面的朋友回答的挺全面的,主要从以下方面入手:
1、权限管理层面:
(1)建议禁止root账户执行应用,使用linux nobody启动redis服务
(2)禁用危险命令:
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""
rename-command KEYS ""
2、账户管理层面:
设置密码访问,比方:requirepass "password"或 >CONFIG set requirepass "password"
3、网络配置层面:
(1)禁止外网访问,bind 指定ip
(2)更改port值,建议采用不常用的端口地址
4、应用本身层面:
关注与redis应用相关的组件漏洞,并及时打补丁
5、其他相关层面
以上内容来自社区交流活动中会员的分享,由社区专家姜文浩汇编。
相关阅读:
社区“Redis”主题下,有精品文章、资料和大量问答,您可以点击阅读原文,或前往如下地址浏览:
http://www.talkwithtrend.com/Topic/91/blog
长按二维码关注公众号